diff --git a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGeneratorExtensions.cs b/src/Hl7.Fhir.Base/Specification/Snapshot/SnapshotGeneratorExtensions.cs similarity index 68% rename from src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGeneratorExtensions.cs rename to src/Hl7.Fhir.Base/Specification/Snapshot/SnapshotGeneratorExtensions.cs index b1b8688e5c..3cd2cb0abb 100644 --- a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGeneratorExtensions.cs +++ b/src/Hl7.Fhir.Base/Specification/Snapshot/SnapshotGeneratorExtensions.cs @@ -7,7 +7,7 @@ */ using Hl7.Fhir.Model; -using Hl7.Fhir.Support; +using Hl7.Fhir.Rest; using Hl7.Fhir.Utility; using System; using System.Collections.Generic; @@ -19,7 +19,7 @@ namespace Hl7.Fhir.Specification.Snapshot // This extension indicates snapshot elements with associated differential constraints in the profile. // Note: extensions are persisted to XML/JSON, whereas annotations are ephemeral (in-memory only) - /// Helper methods for the class to generate and inspect custom extensions. + /// Helper methods for the SnapshotGenerator class to generate and inspect custom extensions. public static class SnapshotGeneratorExtensions { /// The canonical url of the extension definition that marks snapshot elements with associated differential constraints. @@ -54,6 +54,7 @@ public static void RemoveConstrainedByDiffExtension(this IExtendable element) } /// Recursively removes all instances of the extension from the specified element definition and all it's child objects. + [Obsolete("Use RemoveAllNonInheritableExtensions(this Element element) instead.")] public static void RemoveAllConstrainedByDiffExtensions(this Element element) { if (element == null) { throw Error.ArgumentNull(nameof(element)); } @@ -65,6 +66,7 @@ public static void RemoveAllConstrainedByDiffExtensions(this Element element) } /// Recursively removes all instances of the extension from all the elements and their respective child objects. + [Obsolete("Use RemoveAllNonInheritableExtensions(this IEnumerable elements) instead.")] public static void RemoveAllConstrainedByDiffExtensions(this IEnumerable elements) where T : Element { if (elements == null) { throw Error.ArgumentNull(nameof(elements)); } @@ -74,6 +76,47 @@ public static void RemoveAllConstrainedByDiffExtensions(this IEnumerable e } } + + internal static void RemoveAllNonInheritableExtensions(this Element element) + { + if (element == null) { throw Error.ArgumentNull(nameof(element)); } + element.RemoveNonInheritableExtensions(); + foreach (var child in element.Children.OfType()) + { + child.RemoveAllNonInheritableExtensions(); + } + } + + internal static void RemoveNonInheritableExtensions(this IExtendable element) + { + if (element == null) { throw Error.ArgumentNull(nameof(element)); } + foreach (var ext in _nonInheritableExtensions) + { + element.RemoveExtension(ext); + } + } + + private static readonly List _nonInheritableExtensions = [ + ResourceIdentity.CORE_BASE_URL + "elementdefinition-isCommonBinding", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-fmm", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-fmm-no-warnings", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-hierarchy", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-interface", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-normative-version", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-applicable-version", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-category", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-codegen-super", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-security-category", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-standards-status", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-summary", + ResourceIdentity.CORE_BASE_URL + "structuredefinition-wg", + ResourceIdentity.CORE_BASE_URL + "replaces", + ResourceIdentity.CORE_BASE_URL + "resource-approvalDate", + ResourceIdentity.CORE_BASE_URL + "resource-effectivePeriod", + ResourceIdentity.CORE_BASE_URL + "resource-lastReviewDate", + CONSTRAINED_BY_DIFF_EXT //this is our own extension to define differences compared to the base, this can't be inherited from the base profile + ]; + // ========== For internal use only ========== // [WMR 20170209] OBSOLETE #if false diff --git a/src/Hl7.Fhir.Conformance/CompatibilitySuppressions.xml b/src/Hl7.Fhir.Conformance/CompatibilitySuppressions.xml new file mode 100644 index 0000000000..50df2e8381 --- /dev/null +++ b/src/Hl7.Fhir.Conformance/CompatibilitySuppressions.xml @@ -0,0 +1,18 @@ + + + + + CP0001 + T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions + lib/net8.0/Hl7.Fhir.Conformance.dll + lib/net8.0/Hl7.Fhir.Conformance.dll + true + + + CP0001 + T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions + lib/netstandard2.0/Hl7.Fhir.Conformance.dll + lib/netstandard2.0/Hl7.Fhir.Conformance.dll + true + + \ No newline at end of file diff --git a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs b/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs index e34c273918..87d34e30b7 100644 --- a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs +++ b/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs @@ -465,7 +465,7 @@ private async Tasks.Task> generate(StructureDefinition s // [WMR 20170208] Moved to *AFTER* ensureBaseComponents - emits annotations... // [WMR 20160915] Derived profiles should never inherit the ChangedByDiff extension from the base structure - snapshot.Element.RemoveAllConstrainedByDiffExtensions(); + snapshot.RemoveAllNonInheritableExtensions(); snapshot.Element.RemoveAllConstrainedByDiffAnnotations(); // Notify observers @@ -1487,7 +1487,7 @@ private static bool copyChildren(ElementDefinitionNavigator nav, ElementDefiniti var elem = elems[pos]; // [WMR 20160826] Never inherit Changed extension from base profile! - elem.RemoveAllConstrainedByDiffExtensions(); + elem.RemoveAllNonInheritableExtensions(); elem.RemoveAllConstrainedByDiffAnnotations(); // [WMR 20160902] Initialize empty ElementDefinition.Base components if necessary diff --git a/src/Hl7.Fhir.STU3/CompatibilitySuppressions.xml b/src/Hl7.Fhir.STU3/CompatibilitySuppressions.xml new file mode 100644 index 0000000000..4c6b9c5302 --- /dev/null +++ b/src/Hl7.Fhir.STU3/CompatibilitySuppressions.xml @@ -0,0 +1,18 @@ + + + + + CP0001 + T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions + lib/net8.0/Hl7.Fhir.STU3.dll + lib/net8.0/Hl7.Fhir.STU3.dll + true + + + CP0001 + T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions + lib/netstandard2.0/Hl7.Fhir.STU3.dll + lib/netstandard2.0/Hl7.Fhir.STU3.dll + true + + \ No newline at end of file diff --git a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs b/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs index 80dab2d014..8b2616a871 100644 --- a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs +++ b/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs @@ -399,7 +399,8 @@ private async Tasks.Task> generate(StructureDefinition s // [WMR 20170208] Moved to *AFTER* ensureBaseComponents - emits annotations... // [WMR 20160915] Derived profiles should never inherit the ChangedByDiff extension from the base structure - snapshot.Element.RemoveAllConstrainedByDiffExtensions(); + // Also remove core extensions that are not supposed to be inherited by derived profiles + snapshot.RemoveAllNonInheritableExtensions(); snapshot.Element.RemoveAllConstrainedByDiffAnnotations(); // Notify observers @@ -1309,7 +1310,7 @@ private static bool copyChildren(ElementDefinitionNavigator nav, ElementDefiniti var elem = elems[pos]; // [WMR 20160826] Never inherit Changed extension from base profile! - elem.RemoveAllConstrainedByDiffExtensions(); + elem.RemoveAllNonInheritableExtensions(); elem.RemoveAllConstrainedByDiffAnnotations(); // [WMR 20160902] Initialize empty ElementDefinition.Base components if necessary diff --git a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGeneratorExtensions.cs b/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGeneratorExtensions.cs deleted file mode 100644 index 2c13de5f28..0000000000 --- a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGeneratorExtensions.cs +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2017, Firely (info@fire.ly) and contributors - * See the file CONTRIBUTORS for details. - * - * This file is licensed under the BSD 3-Clause license - * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE - */ - -using Hl7.Fhir.Model; -using Hl7.Fhir.Support; -using Hl7.Fhir.Utility; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Hl7.Fhir.Specification.Snapshot -{ - // [WMR 20170209] cf. ConstrainedByDifferentialAnnotation - // This extension indicates snapshot elements with associated differential constraints in the profile. - // Note: extensions are persisted to XML/JSON, whereas annotations are ephemeral (in-memory only) - - /// Helper methods for the class to generate and inspect custom extensions. - public static class SnapshotGeneratorExtensions - { - /// The canonical url of the extension definition that marks snapshot elements with associated differential constraints. - // public static readonly string CHANGED_BY_DIFF_EXT = "http://hl7.org/fhir/StructureDefinition/changedByDifferential"; - public static readonly string CONSTRAINED_BY_DIFF_EXT = "http://hl7.org/fhir/StructureDefinition/constrainedByDifferentialExtension"; - - /// - /// Decorate the specified snapshot element definition with a special extension - /// to indicate that the element is constrained by the differential. - /// - /// An instance. - /// An optional boolean value (default true). - /// Sets the extension to store the boolean flag. - internal static void SetConstrainedByDiffExtension(this IExtendable element, bool value = true) - { - if (element == null) { throw Error.ArgumentNull(nameof(element)); } - element.SetBoolExtension(CONSTRAINED_BY_DIFF_EXT, value); - } - - /// Determines if the snapshot element was decorated with an extension indicating the element is constrained by the differential. - /// An instance. - /// A boolean value, or null. - /// Gets the boolean flag from the extension, if it exists. - public static bool? GetConstrainedByDiffExtension(this IExtendable element) => element.GetBoolExtension(CONSTRAINED_BY_DIFF_EXT); - - /// Removes the extension from the specified element definition. - public static void RemoveConstrainedByDiffExtension(this IExtendable element) - { - if (element == null) { throw Error.ArgumentNull(nameof(element)); } - element.RemoveExtension(CONSTRAINED_BY_DIFF_EXT); - } - - /// Recursively removes all instances of the extension from the specified element definition and all it's child objects. - public static void RemoveAllConstrainedByDiffExtensions(this Element element) - { - if (element == null) { throw Error.ArgumentNull(nameof(element)); } - element.RemoveConstrainedByDiffExtension(); - foreach (var child in element.Children.OfType()) - { - child.RemoveAllConstrainedByDiffExtensions(); - } - } - - /// Recursively removes all instances of the extension from all the elements and their respective child objects. - public static void RemoveAllConstrainedByDiffExtensions(this IEnumerable elements) where T : Element - { - if (elements == null) { throw Error.ArgumentNull(nameof(elements)); } - foreach (var elem in elements) - { - elem.RemoveAllConstrainedByDiffExtensions(); - } - } - - // ========== For internal use only ========== - // [WMR 20170209] OBSOLETE -#if false - - /// Removes a specific extension from the snapshot element definition and it's descendant elements, recursively. - /// An instance. - /// The canonical url of the extension. - static void ClearAllExtensions(this ElementDefinition elemDef, string uri) - { - if (elemDef != null) - { - ClearExtensions(elemDef, uri); - } - } - - static void ClearExtensions(this IEnumerable elements, string uri) where T : Base - { - if (elements != null) - { - foreach (var child in elements) - { - ClearExtensions(child, uri); - } - } - } - - static void ClearExtensions(this T element, string uri) where T : Base - { - if (element != null) - { - ClearExtension(element as IExtendable, uri); - ClearExtensions(element.Children, uri); - } - } - - static void ClearExtension(this IExtendable extendable, string uri) - { - extendable?.RemoveExtension(uri); - } -#endif - - } -} diff --git a/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs b/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs index 987dce7f65..13814b8cfd 100644 --- a/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs +++ b/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs @@ -21,8 +21,8 @@ using Hl7.Fhir.Support; using Hl7.Fhir.Utility; using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; using NSubstitute; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -2433,8 +2433,8 @@ private static bool isAlmostExactly(ElementDefinition elem, ElementDefinition ba } // Also ignore any Changed extensions on base and diff - elemClone.RemoveAllConstrainedByDiffExtensions(); - baseClone.RemoveAllConstrainedByDiffExtensions(); + elemClone.RemoveAllNonInheritableExtensions(); + baseClone.RemoveAllNonInheritableExtensions(); elemClone.RemoveAllConstrainedByDiffAnnotations(); baseClone.RemoveAllConstrainedByDiffAnnotations(); diff --git a/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorTest.cs b/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorTest.cs index 01215cc363..dab716a337 100644 --- a/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorTest.cs +++ b/src/Hl7.Fhir.Specification.Shared.Tests/Snapshot/SnapshotGeneratorTest.cs @@ -2562,8 +2562,8 @@ private static bool isAlmostExactly(ElementDefinition elem, ElementDefinition ba } // Also ignore any Changed extensions on base and diff - elemClone.RemoveAllConstrainedByDiffExtensions(); - baseClone.RemoveAllConstrainedByDiffExtensions(); + elemClone.RemoveAllNonInheritableExtensions(); + baseClone.RemoveAllNonInheritableExtensions(); elemClone.RemoveAllConstrainedByDiffAnnotations(); baseClone.RemoveAllConstrainedByDiffAnnotations(); @@ -10155,6 +10155,37 @@ private StructureDefinition createVeryNestedExtension() } + [TestMethod] + public void RemoveNonInhertitableSnapshotsTest() + { + var profile = new StructureDefinition + { + Url = "http://fire.ly/StructureDefinition/example", + Snapshot = new() + { + Element = new() { + new("Example") + { + Binding = new() + { + Strength = BindingStrength.Required, + ValueSet = "http://fire.ly/ValueSet/example" + } + }, + } + } + }; + + profile.Snapshot.Element[0].AddExtension(ResourceIdentity.CORE_BASE_URL + "structuredefinition-hierarchy", new FhirString("foo")); + profile.Snapshot.Element[0].Binding.AddExtension(ResourceIdentity.CORE_BASE_URL + "elementdefinition-isCommonBinding", new FhirBoolean(true)); + + profile.Snapshot.RemoveAllNonInheritableExtensions(); + + profile.Snapshot.Element[0].Extension.Should().BeEmpty(); + profile.Snapshot.Element[0].Binding.Extension.Should().BeEmpty(); + } + + [TestMethod] public async Tasks.Task TestNewR5Elements() {